package services

import (
	"context"
	"github.com/pkg/errors"
	"go.didapinche.com/foundation/plat-echo/app/ops/models"
	"go.didapinche.com/foundation/plat-echo/app/ops/models/response"
	"go.didapinche.com/foundation/plat-echo/app/ops/repositories"
	"go.didapinche.com/foundation/plat-echo/app/ops/zclients"
	"go.didapinche.com/goapi/user_department_service_api"
	"go.didapinche.com/time"
	"go.uber.org/zap"
)

type AlertCurrentService interface {
	FindByGroupAndLevel(ctx context.Context, group, uid string, level int, start, end time.Time) ([]*models.AlertCurrent, error)
	FindByAppID(ctx context.Context, appID uint64, start, end time.Time) ([]*models.AlertCurrent, error)
	FindByDate(ctx context.Context, end time.Time) ([]*response.AlertRecordResp, error)
}

type alertCurrentService struct {
	repository      repositories.AlertCurrentRepository
	apiRepository   repositories.ApiRepository
	appRepository   repositories.ApplicationRepository
	department      user_department_service_api.TChanDepartmentService
	graphRepository repositories.GraphRepository
	logger          *zap.Logger
}

func NewAlertCurrentService(repository repositories.AlertCurrentRepository,
	graphRepository repositories.GraphRepository,
	department user_department_service_api.TChanDepartmentService,
	apiRepository repositories.ApiRepository,
	appRepository repositories.ApplicationRepository,
	logger *zap.Logger) AlertCurrentService {
	return &alertCurrentService{
		repository:      repository,
		logger:          logger,
		appRepository:   appRepository,
		department:      department,
		apiRepository:   apiRepository,
		graphRepository: graphRepository,
	}
}
func (s alertCurrentService) FindByGroupAndLevel(ctx context.Context, group, uid string, level int, start, end time.Time) ([]*models.AlertCurrent, error) {
	if group == "" {
		group = "group-2"
	}

	groups, err := zclients.GetNodeIDs(ctx, s.department, group)
	if err != nil {
		s.logger.Error("call zclients.GetNodeIDs error", zap.Error(err))
		return nil, errors.Wrap(err, "call zclients.GetNodeIDs error")
	}
	alerts, err := s.repository.FindByGroupAndLevel(ctx, groups, level, start, end)
	if err != nil {
		s.logger.Error("call AlertCurrentRepository.FindByGroupAndLevel error", zap.Error(err))
		return nil, errors.Wrap(err, "call AlertCurrentRepository.FindByGroupAndLevel error")
	}
	for _, a := range alerts {

		a.Duration = time.Now().Sub(a.StartAlertTime.Time).String()
		if a.Alerts != nil && len(*a.Alerts) > 0 {
			(*a.Alerts)[0].StartAlertTime = a.StartAlertTime
			(*a.Alerts)[0].Value = string((*a.Alerts)[0].Annotations["value"])
		}
		if a.ApiID != 0 {
			api, err := s.apiRepository.FindByID(ctx, a.ApiID)
			if err != nil {
				s.logger.Error("call apiRepository FindByID", zap.Error(err))
				continue
			}
			a.ApiInfo = api
			if api.Type == 0 {
				api.TemplateType = 1
				a.TemplateType = 1
			} else {
				api.TemplateType = 2
				a.TemplateType = 2
			}
			a.App = api.AppName
		} else if a.AppID != 0 {
			app, err := s.appRepository.FindByID(ctx, a.AppID)
			if err != nil {
				s.logger.Error("call appRepository FindByID", zap.Error(err))
				continue
			}
			a.AppInfo = app
			a.App = app.Name
		}
	}
	if uid != "" {
		alerts2 := make([]*models.AlertCurrent, 0)
		for i, _ := range alerts {
			if alerts[i].AppInfo != nil {
				for _, o := range alerts[i].AppInfo.GetOwners() {
					if o.UserID == uid {
						alerts2 = append(alerts2, alerts[i])
					}
				}
			} else if alerts[i].ApiInfo != nil {
				for _, o := range alerts[i].ApiInfo.GetOwners() {
					if o.UserID == uid {
						alerts2 = append(alerts2, alerts[i])
					}
				}
			}

		}
		return alerts2, nil
	}

	return alerts, nil
}

func (s alertCurrentService) FindByAppID(ctx context.Context, appID uint64, start, end time.Time) ([]*models.AlertCurrent, error) {
	alerts, err := s.repository.FindByAppID(ctx, int(appID), start, end)
	if err != nil {
		s.logger.Error("call alertCurrentService FindByAppID error", zap.Error(err))
		return nil, errors.Wrap(err, "call alertCurrentService FindByAppID error")
	}
	return alerts, err
}

func (s alertCurrentService) FindByDate(ctx context.Context, end time.Time) ([]*response.AlertRecordResp, error) {
	alerts, err := s.repository.FindByDate(ctx, end)
	if err != nil {
		s.logger.Error("call alertCurrentService FindByAppID error", zap.Error(err))
		return nil, errors.Wrap(err, "call alertCurrentService FindByAppID error")
	}

	for _, a := range alerts {
		graph, err := s.graphRepository.FindByID(ctx, a.GraphID)
		if err != nil {
			continue
		}
		if graph.Alert != nil && graph.Alert.Receiver != nil && len(graph.Alert.Receiver.Dingdings) > 0 {
			a.Token = graph.Alert.Receiver.Dingdings[0].Token
		}
		if graph.General != nil {
			a.Format = graph.General.Yaxes.Format
		}
		if a.AppID != 0 {
			app, err := s.appRepository.FindByID(ctx, a.AppID)
			if err != nil {
				continue
			}
			owner := make([]string, 0)
			for _, user := range app.GetOwners() {
				owner = append(owner, user.UserName)
			}
			a.Owners = owner
			a.AppName = app.Name
		} else if a.ApiID != 0 {
			api, err := s.apiRepository.FindByID(ctx, a.ApiID)
			if err != nil {
				s.logger.Error("call apiRepository FindByAppID error", zap.Error(err))
				return nil, errors.Wrap(err, "call apiRepository FindByAppID error")
			}
			owner := make([]string, 0)
			for _, user := range api.GetOwners() {
				owner = append(owner, user.UserName)
			}
			a.Owners = owner
			a.AppName = api.AppName
			if api.Type == 0 {
				a.ApiName = api.HttpMethod + ":" + api.HttpPath
			} else if api.Type == 1 {
				a.ApiName = api.ZeusService + "" + api.ZeusMethod
			}
		}
	}
	alerts2 := response.MakeCurrentAlertRecordResps(alerts)
	return alerts2, err
}
